﻿using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NewRetail.Application.Components.WeChat.Configurations;
using NewRetail.Application.Components.WeChat.Model;
using NewRetail.Application.Components.WeChat.Services.HttpClients;
using NewRetail.Application.Utility;
using SKIT.FlurlHttpClient.Wechat.Api;
using SKIT.FlurlHttpClient.Wechat.Api.Events;
using SKIT.FlurlHttpClient.Wechat.TenpayV3;
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models;
using System;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;

namespace NewRetail.Application.Components.WeChat.Services
{
    #region 微信回调消息接口
    /// <summary>
    /// 微信回调消息接口
    /// </summary>
    public interface IWeChatNotifyService : IApplicationService
    {
        /// <summary>
        /// 签名检验。
        /// </summary>
        /// <param name="signature">微信加密签名，signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。</param>
        /// <param name="timestamp">时间戳</param>
        /// <param name="nonce">随机数</param>
        /// <param name="appId">appId</param>
        /// <returns>检验成功则返回true，否则返回false。</returns>
        bool Check(string signature, string timestamp, string nonce, string appId);

        /// <summary>
        /// 接收微信服务器推送
        /// </summary>
        /// <param name="content"></param>
        /// <param name="appId"></param>
        /// <returns></returns>
        Task<string> WxResponseMessage(string content, string appId);
        //string WxResponse(HttpRequest request);
        /// <summary>
        /// 设置消息通知地址
        /// </summary>
        /// <returns></returns>
        Task<(string, string)> UpdateMarketingFavorCallback();
        /// <summary>
        /// 签名检验。
        /// </summary>
        /// <param name="signature">微信加密签名</param>
        /// <param name="timestamp">时间戳</param>
        /// <param name="nonce">随机数</param>
        /// <param name="merchantId">商户id</param>
        /// <param name="serialNumber">平台证书序列号</param>
        /// <param name="content">微信推送的数据</param>
        /// <returns>检验成功则返回true，否则返回false。</returns>
        bool VerifyEventSignature(string signature, string timestamp, string nonce, string merchantId, string serialNumber, string content);
        /// <summary>
        /// 核销券时候将用户券状态改掉
        /// </summary>
        /// <param name="content"></param>
        /// <param name="merchantId"></param>
        /// <returns></returns>
        Task<string> WxPayNotifyResponseMessage(string content, string merchantId);
    }
    #endregion

    #region 微信回调消息实现
    public class WeChatNotifyService : ApplicationService, IWeChatNotifyService
    {
        #region Field
        private readonly IWeChatApiHttpClientFactory _wechatApiHttpClientFactory;        
        private readonly IReplySetService _replySetService;
        private readonly ILogger _logger;
        private readonly WxpayOptions _wechatPayOptions;
        //private readonly IHttpContextAccessor _accessor;
        private readonly IWechatTenpayHttpClientFactory _wechatTenpayHttpClientFactory;
        #endregion

        #region 构造函数
        public WeChatNotifyService(IWeChatApiHttpClientFactory wechatApiHttpClientFactory, IReplySetService replySetService,
            IWechatTenpayHttpClientFactory wechatTenpayHttpClientFactory, IOptions<WxpayOptions> wechatPayOptions, 
            ILogger<WeChatNotifyService> logger/*, IHttpContextAccessor accessor*/)
        {
            _wechatApiHttpClientFactory = wechatApiHttpClientFactory;
            _replySetService = replySetService;
            _logger = logger;
            //_accessor = accessor;
            _wechatPayOptions = wechatPayOptions.Value;
            _wechatTenpayHttpClientFactory = wechatTenpayHttpClientFactory;
        }
        #endregion

        #region Implementation of ISignatureService

        #region 签名检验
        /// <summary>
        /// 签名检验。
        /// </summary>
        /// <param name="signature">微信加密签名，signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。</param>
        /// <param name="timestamp">时间戳</param>
        /// <param name="nonce">随机数</param>
        /// <param name="appId">appId</param>
        /// <returns>检验成功则返回true，否则返回false。</returns>
        public bool Check(string signature, string timestamp, string nonce, string appId)
        {
            var client = _wechatApiHttpClientFactory.Create(appId);
            try
            {
                //时间戳不能为空
                if (string.IsNullOrEmpty(timestamp))
                    return false;
                bool valid = client.VerifyEventSignatureForEcho(callbackTimestamp: timestamp, callbackNonce: nonce, callbackSignature: signature);
                return valid;
            }
            catch(Exception e)
            {
                _logger.LogError(message: e.Message, exception: e);
                throw;
            }
        }
        #endregion

        #region 接收微信服务器推送
        /// <summary>
        /// 接收微信服务器推送
        /// </summary>
        /// <param name="content"></param>
        /// <param name="appId"></param>
        /// <returns></returns>
        public async Task<string> WxResponseMessage(string content, string appId)
        {
            var result = "";
            try
            {
                var client = _wechatApiHttpClientFactory.Create(appId);
                var msgType = client.DeserializeEventFromXml(content).MessageType;
                switch (msgType)
                {
                    case "text":
                        {
                            //var eventModel = client.DeserializeEventFromXml<TextMessageEvent>(content);
                            //text请求回调
                            result = await _replySetService.OnTextRequest(content);
                            _logger.LogInformation("text回调：" + content);
                        }
                        break;

                    case "image":
                        {
                            var eventModel = client.DeserializeEventFromXml<ImageMessageEvent>(content);
                            // Do Something
                        }
                        break;
                    case "event":
                        {
                            //var eventModel = client.DeserializeEventFromXml<ScanPushEvent>(content);
                            result = await _replySetService.OnEventRequest(content, client, appId);
                            _logger.LogInformation("event回调：" + content);
                        }
                        break;
                }
            }
            catch(Exception e)
            {
                _logger.LogError("event回调异常：" + e.Message);
                return "";
            }
            return result;
        }
        #endregion

        #region 删除
        ///// <summary>
        ///// 处理请求，产生响应
        ///// </summary>
        ///// <returns></returns>
        //public string WxResponse(HttpRequest request)
        //{
        //    var reader = System.Xml.XmlReader.Create(request.Body);
        //    var doc = XDocument.Load(reader);
        //    var xml = doc.Element("xml");
        //    //获取MsgType
        //    string msgType = xml.Element("MsgType").Value;
        //    string sXml = doc.ToString();
        //    switch (msgType.Trim())
        //    {
        //        case "event"://如果是事件
        //            return "ev";
        //        case "text"://如果是文本消息
        //            var result = OnReceiveTextMsg(sXml);
        //            return result;
        //        default:
        //            return "不被支持的关键字！";
        //    }
        //}
        ///// <summary>
        ///// 响应文本消息
        ///// </summary>
        ///// <param name="xml"></param>
        ///// <returns></returns>
        //private static string OnReceiveTextMsg(string xml)
        //{
        //    WxTextMsg msg = XmlEntityExchange<WxTextMsg>.ConvertXml2Entity(xml);
        //    //返回消息，互换收发用户
        //    string toUser = msg.FromUserName;
        //    msg.FromUserName = msg.ToUserName;
        //    msg.ToUserName = toUser;

        //    switch (msg.Content.Trim())
        //    {
        //        case "?":
        //            msg.Content = "ewf";
        //            break;
        //        case "？":
        //            msg.Content = "fff";
        //            break;
        //        case "1":
        //            msg.Content = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        //            break;
        //        case "2":
        //            msg.Content = "获取天气正在维护";
        //            break;
        //        case "3":
        //            msg.Content = "来吧，想唠点什么呢？ [偷笑]";
        //            break;
        //        case "你是男的女的":
        //            msg.Content = "姑娘一枚 [偷笑]";
        //            break;
        //        case "id":
        //            msg.Content = toUser;
        //            break;
        //        default:
        //            msg.Content = "抱歉哦，我不认识您输入的命令。/害羞 /:,@-D";
        //            break;
        //    }
        //    return XmlEntityExchange<WxTextMsg>.ConvertEntity2Xml(msg);
        //}
        #endregion

        #region 微信支付回调相关

        #region 设置消息通知地址
        /// <summary>
        /// 设置消息通知地址
        /// </summary>
        /// <returns></returns>
        public async Task<(string, string)> UpdateMarketingFavorCallback()
        {
            var errMsg = "";
            //商户号
            var merchantId = _wechatPayOptions.Merchants?.FirstOrDefault().MerchantId;
            //通知url地址。在appsetting.json文件中配置。校验规则：1、notify_url必须为https   2、地址要是一个可访问的地址   3、不能携带参数。示例： “https://pay.weixin.qq.com/wxpay/pay.action”
            var notifyUrl = string.Format(_wechatPayOptions.NotifyUrl, merchantId);
            var request = new UpdateMarketingFavorCallbackRequest()
            {
                MerchantId = merchantId,
                NotifyUrl = notifyUrl,
                Switch = false
            };
            var wechatTenpayClient = _wechatTenpayHttpClientFactory.Create(merchantId);
            var responseInfo = await wechatTenpayClient.ExecuteUpdateMarketingFavorCallbackAsync(request);
            if (!responseInfo.IsSuccessful())
            {
                errMsg = responseInfo.ErrorMessage;
                _logger.LogWarning(
                    "设置消息通知地址失败（状态码：{0}，错误代码：{1}，错误描述：{2}）。",
                    responseInfo.RawStatus, responseInfo.ErrorCode, responseInfo.ErrorMessage
                );
            }
            return (responseInfo.NotifyUrl, errMsg);
        }
        #endregion

        #region 签名检验
        /// <summary>
        /// 签名检验。
        /// </summary>
        /// <param name="signature">微信加密签名</param>
        /// <param name="timestamp">时间戳</param>
        /// <param name="nonce">随机数</param>
        /// <param name="merchantId">商户id</param>
        /// <param name="serialNumber">平台证书序列号</param>
        /// <param name="content">微信推送的数据</param>
        /// <returns>检验成功则返回true，否则返回false。</returns>
        public bool VerifyEventSignature(string signature, string timestamp, string nonce, string merchantId, string serialNumber, string content)
        {
            bool valid = false;
            var client = _wechatTenpayHttpClientFactory.Create(merchantId);
            try
            {
                //时间戳不能为空
                if (string.IsNullOrEmpty(timestamp))
                    return valid;
                valid = client.VerifyEventSignature(callbackTimestamp: timestamp, callbackNonce: nonce, callbackBody: content, callbackSignature: signature, callbackSerialNumber: serialNumber);
                valid = true;
            }
            catch (Exception e)
            {
                _logger.LogError(message: e.Message, exception: e);
            }
            return valid;
        }
        #endregion

        #region 微信支付通知回调
        /// <summary>
        /// 微信支付通知回调
        /// </summary>
        /// <param name="content"></param>
        /// <param name="merchantId"></param>
        /// <returns></returns>
        public async Task<string> WxPayNotifyResponseMessage(string content, string merchantId)
        {
            var result = "";
            try
            {
                var client = _wechatTenpayHttpClientFactory.Create(merchantId);
                //请求回调
                result = await _replySetService.OnWriteOffEventRequest(content, client, merchantId);
                _logger.LogInformation("回调：" + content);
            }
            catch(Exception e)
            {
                _logger.LogError(message: e.Message, exception: e);
            }
            return result;
        }
        #endregion

        #endregion

        #endregion
    }
    #endregion
}
